#ifndef SCENE_HPP
#define SCENE_HPP

#include <vector>

#include "object.hpp"

using SkyFn = std::function<Eigen::Vector3f(const Eigen::Vector3f &)>;

class Scene
{
    struct Node
    {
        Eigen::Vector3f min;
        Eigen::Vector3f max;
    };

    struct Face
    {
        int object_idx;
        int face_idx;
    };

    struct FaceAndCenter
    {
        Face face;
        Eigen::Vector3f center;
    };

    std::vector<Object> objects;
    SkyFn sky;
    std::vector<Node> tree;
    std::vector<std::vector<Face>> faces;

    void box(
        std::vector<FaceAndCenter>::const_iterator begin,
        std::vector<FaceAndCenter>::const_iterator end,
        Eigen::Vector3f & min,
        Eigen::Vector3f & max) const;
    void partition(
        int node,
        std::vector<FaceAndCenter>::iterator begin,
        std::vector<FaceAndCenter>::iterator end,
        int level);
    void intersect(
        int node,
        const Eigen::Vector3f & ray_o,
        const Eigen::Vector3f & ray_d,
        float & res_dist,
        Face & res_face) const;

public:
    explicit Scene(std::vector<Object> && objects_, SkyFn sky_);
    const std::vector<Object> & get_objects() const { return objects; }
    void intersect(
        const Eigen::Vector3f & ray_o,
        const Eigen::Vector3f & ray_d,
        float & dist,
        int & object_idx,
        int & face_idx,
        Eigen::Vector3f & sky_color) const;
};

#endif
